#################################################################################################
#
#
# QGCM Model Makefile
#
#
#################################################################################################

# Use ./compile to compile the model
# use the debug flag to compile debug code
# use the opt flag to compile optimized code
# parallel switch to make omp parallelized code
# serial otherwise

CXX=g++
CDIR=$(CURDIR)

ifndef MATLABROOT
    $(error Please define variable MATLABROOT to point to a valid MATLAB installation.)
endif

MEX=$(MATLABROOT)/bin/mex
CC=g++
FC=gfortran
MAKEDEPEND=makedepend

HOMEDIR=`echo ~`

ifdef DISPLAY_VECTORIZE_INFORMATION
  VECLEVEL=$(DISPLAY_VECTORIZE_INFORMATION)
else
  VECLEVEL=0
endif

ifdef SINGLEPRECISION
      CPRECFLAG=-fsingle-precision-constant
      MEXPRECFLAG=
      FPRECFLAG=
else
      MEXPRECFLAG=-D__QGCMDOUBLEPRECISION=true
      CPRECFLAG=-D__QGCMDOUBLEPRECISION=true
      FPRECFLAG=$(CPRECFLAG)
endif

MEXOPTS=-f $(MATLABROOT)/bin/matopts.sh -largeArrayDims $(MEXPRECFLAG)
MEXLIBDIR=-L$(MATLABROOT)/bin/glnxa64

PARFLAGS=-fopenmp
SERFLAGS=-D SERIALQGCM 

OCPPFLAGS=-O3 --param inline-unit-growth=100 --param max-inline-insns-single=3050 -ftree-vectorizer-verbose=$(VECLEVEL) -Wconversion -Winline $(CPRECFLAG) -D NDEBUG -save-temps 
DCPPFLAGS= -ggdb3 $(CPRECFLAG) -fbounds-check -Wall -Winline -fno-default-inline -D DEBUG -D_GLIBCXX_DEBUG -g3 -fno-inline -O0 -save-temps

OMEXFLAGS=-c
DMEXFLAGS=-g -c -DDEBUG -D_GLIBCXX_DEBUG
 
NVCPPFLAGS=-O2 -Wconversion $(CPRECFLAG) -D NDEBUG -finline-functions -funswitch-loops -fpredictive-commoning -fgcse-after-reload

DFFLAGS=-ggdb3 -c -x f95-cpp-input -ffree-form -fbounds-check $(CPRECFLAG)
OFFLAGS=-c -g -O3 -x f95-cpp-input -ffree-form $(CPRECFLAG) 

NETCDFINC=#-L
NETCDFLIBDIR=#-L

CURLDIR=#-L/local-ssd/dandrade/junk/curl/lib

HDF5LIBDIR=#-L

MPDIR=./ParserX
MPLIBDIR=-L$(MPDIR)
MPINCDIR=-I$(MPDIR)

TESTDIR=$(CDIR)/CPPUnitTests
TESTLIB=-L$(TESTDIR)
TESTINCDIR=-I$(TESTDIR)

LIBDIR=-L/usr/lib -L$(HOMEDIR)/lib $(MPLIBDIR) $(HDF5LIBDIR) $(NETCDFLIBDIR) $(CURLDIR) 
MULIB=muParser
MPLIB=mpParser

MEXINC=-I$(MATLABROOT)/extern/include/
MEXLIB=-Wl,-rpath-link,$(MATLABROOT)/bin/glnxa64 $(MEXLIBDIR) -lmx -lmex -lmat -lm
ifdef DEBUG
LIB=-l$(MPLIB)_$(dflag) -lstdc++ -lreadline -lsupc++ -lgfortran -lcurl -lnetcdf_c++ -lnetcdf -lcurses -lz -Wl,-Bstatic -Wl,-Bdynamic -lhdf5_hl -lhdf5 $(MEXLIB)
INCDIR=$(MPINCDIR) $(NETCDFINC) $(MEXINC)
else
LIB=-l$(MPLIB)_$(dflag) -lstdc++ -lreadline -lsupc++ -lgfortran -lcurl -lnetcdf_c++ -lnetcdf -lcurses -lz -Wl,-Bstatic -Wl,-Bdynamic -lhdf5_hl -lhdf5 $(MEXLIB)
INCDIR=$(MPINCDIR) $(NETCDFINC) $(MEXINC)
endif

ifdef DEBUG
  dflag=dbg
  ext=g
  FFLAGS=$(DFFLAGS) 
  CPPFLAGS=$(DCPPFLAGS) 
  MEXFLAGS=$(MEXOPTS) $(DMEXFLAGS)
else
 ifdef NOVECTORIZE
  dflag=novec_opt
  ext=nv_o
  FFLAGS=$(OFFLAGS)
  CPPFLAGS=$(NVCPPFLAGS)
  MEXFLAGS=$(MEXOPTS) $(OMEXFLAGS)
 else
  dflag=opt
  ext=o
  FFLAGS=$(OFFLAGS)
  CPPFLAGS=$(OCPPFLAGS)
  MEXFLAGS=$(MEXOPTS) $(OMEXFLAGS)
 endif
endif

mexext=mex$(ext)
parext=par$(ext)
serext=ser$(ext)
depext=d$(ext)
depmexext=d$(mexext)
pardepext=par$(depext)
serdepext=ser$(depext)

XQGCMSERLIB=xQGCMSerial$(dflag)
XQGCMPARLIB=xQGCMParallel$(dflag)

MEXOBJS=mexContainer.$(mexext) mexAux.$(mexext)
CPPOBJS = qgcmio.$(ext) misclib.$(ext)  readers.$(ext) qgcmmath.$(ext) psystem.$(ext) integrator.$(ext) diagnostics.$(ext) netcdfaux.$(ext) static.$(ext) diagfuncs.$(ext) diagoperators.$(ext) main_aux.$(ext) preprocessor.$(ext) compiler.$(ext) debugger.$(ext)
PAROBJS = mappers.$(parext) model.$(parext) ssystem.$(parext) datatypes.$(parext)
SEROBJS = mappers.$(serext) model.$(serext) ssystem.$(serext) datatypes.$(serext)
FOBJS = # freaders.$(ext)

default :
	make serial

serial :
	make ctags
	make main_$(dflag)

par :
	make ctags
	make main_par_$(dflag)

parallel :
	make ctags
	make main_par_$(dflag)

-include $(CPPOBJS:.$(ext)=.$(depext)) $(SEROBJS:.$(serext)=.$(serdepext)) $(PAROBJS:.$(parext)=.$(pardepext)) $(FOBJS:.$(ext)=.$(depext))

%.$(ext) : %.f  
	$(FC) -c $(FFLAGS) $(INCDIR) $*.f -o $*.$(ext)
	$(FC) -MM $(FFLAGS) $(INCDIR) $*.f > $*.$(depext)
	@cp -f $*.$(depext) $*.$(depext).tmp
	@sed -e 's/.*://' -e 's/\\$$//' < $*.$(depext).tmp | fmt -1 | \
	  sed -e 's/^ *//' -e 's/$$/:/' >> $*.$(depext)
	@rm -f $*.$(depext).tmp

%.$(ext) : %.cpp
	$(CXX) -c $(CPPFLAGS) $(INCDIR)  $*.cpp -o $*.$(ext)
	$(CXX) -MM $(CPPFLAGS) $(INCDIR) $*.cpp > $*.$(depext)
	@cp -f $*.$(depext) $*.$(depext).tmp
	@sed -e 's/.*://' -e 's/\\$$//' < $*.$(depext).tmp | fmt -1 | \
	  sed -e 's/^ *//' -e 's/$$/:/' >> $*.$(depext)
	@rm -f $*.$(depext).tmp

%.$(mexext) : %.cpp 
	$(MEX) -c $(MEXFLAGS) $(INCDIR) $*.cpp
	@mv $*.o $*.$(mexext)	#@cp -f $*.$(depmexext) $*.$(depmexext).tmp
#	#@sed -e 's/.*://' -e 's/\\$$//' < $*.$(depmexext).tmp | fmt -1 | \ sed -e 's/^ *//' -e 's/$$/:/' >> $*.$(depmexext) #@rm -f $*.$(depmexext).tmp


%.$(serext) : %.cpp
	$(CXX) -c $(CPPFLAGS) $(SERFLAGS) $(INCDIR) $*.cpp -o $*.$(serext)
	$(CXX) -MM $(CPPFLAGS) $(INCDIR) $*.cpp > $*.$(serdepext)
	@cp -f $*.$(serdepext) $*.$(serdepext).tmp
	@sed -e 's/.*://' -e 's/\\$$//' < $*.$(serdepext).tmp | fmt -1 | \
	  sed -e 's/^ *//' -e 's/$$/:/' >> $*.$(serdepext)
	@rm -f $*.$(serdepext).tmp

%.$(parext) : %.cpp 
	$(CXX) -c $(CPPFLAGS) $(PARFLAGS) $(INCDIR) $< -o $@
	$(CXX) -MM $(CPPFLAGS) $(INCDIR) $*.cpp > $*.$(pardepext)
	@cp -f $*.$(pardepext) $*.$(pardepext).tmp
	@sed -e 's/.*://' -e 's/\\$$//' < $*.$(pardepext).tmp | fmt -1 | \
	  sed -e 's/^ *//' -e 's/$$/:/' >> $*.$(pardepext)
	@rm -f $*.$(pardepext).tmp

$(MPDIR)/lib$(MPLIB)_$(dflag).a :
	cd $(MPDIR) && make

tags : *.cpp *.h ./$(MPDIR)/*.cpp ./$(MPDIR)/*.h
	ctags *.h *.cpp ./$(MPDIR)/*.cpp ./$(MPDIR)/*.h

ctags : tags

clean : 
	rm -f main.$(ext) $(MEXOBJS) $(CPPOBJS) $(PAROBJS) $(SEROBJS) $(FOBJS) *.$(depext) *.$(serdepext) *.$(pardepext) *.gch  main_par_$(dflag) main_$(dflag) *.ii *.s
	rm -f tags
	cd $(MPDIR) && make clean
	cd $(TESTDIR) && make clean
	rm -f unitTests_$(dflag)

$(XQGCMSERLIB).a : $(FOBJS) $(CPPOBJS) $(SEROBJS) $(MEXOBJS) $(MPDIR)/lib$(MPLIB)_$(dflag).a
	ar rcs lib$(XQGCMSERLIB).a $(FOBJS) $(CPPOBJS) $(SEROBJS) $(MEXOBJS)

$(XQGCMPARLIB).a : $(FOBJS) $(CPPOBJS) $(SEROBJS) $(MEXOBJS) $(MPDIR)/lib$(MPLIB)_$(dflag).a
	ar rcs lib$(XQGCMPARLIB).a $(FOBJS) $(CPPOBJS) $(PAROBJS) $(MEXOBJS) 

main_$(dflag) : $(FOBJS) $(CPPOBJS) $(SEROBJS) $(MEXOBJS) $(MPDIR)/lib$(MPLIB)_$(dflag).a
	$(CC) $(CPPFLAGS) $(INCDIR) main.cpp -o main_$(dflag) -L./ -l$(XQGCMSERLIB) $(LIBDIR) $(LIB) 

main_par_$(dflag) : main.cpp $(FOBJS) $(CPPOBJS) $(PAROBJS) $(MEXOBJS) $(MPDIR)/lib$(MPLIB)_$(dflag).a
	$(CC) $(CPPFLAGS) $(INCDIR) main.cpp -o main_$(dflag) -L./ -l$(XQGCMPARLIB) $(LIBDIR) $(LIB) 

